﻿using Bnbjoy.Business.Abstract;
using Bnbjoy.Domain.Entities;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace BnbjoyBackend.Api.Provider
{
    public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider, IDisposable
    {
        private IRefreshTokenService _refreshTokenService;

        private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();

        public SimpleRefreshTokenProvider(IRefreshTokenService refreshTokenService)
        {
            _refreshTokenService = refreshTokenService;
        }

        public async Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            //持久化存储refresh token
            //背景：Refresh token只是一种标识，不包含任何信息；
            //而access token是经过序列化并加密的授权信息，发送到服务器时，会被解密并从中读取授权信息。
            //正是因为access token包含的是信息，信息是易变的，所以它的过期时间很短；
            //正是因为refresh token只是一种标识，不易变，所以生命周期可以很长。
            //如果我们将refresh token存储在ConcurrentDictionary类型的静态变量中，只要程序重启，refresh token及相关信息就会丢失。
            //因此需要持久化refresh token信息

            //var clientId = context.OwinContext.Get<string>("as:client_id");
            //if (string.IsNullOrEmpty(clientId)) return;

            if (context.Ticket == null || string.IsNullOrWhiteSpace(context.Ticket.Identity.Name))
                return;

            var clientId = context.Ticket.Properties.Dictionary["as:client_id"];

            if (string.IsNullOrEmpty(clientId))
            {
                return;
            }

            var refreshTokenId = Guid.NewGuid().ToString("n");

            var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");
            if (string.IsNullOrEmpty(refreshTokenLifeTime)) return;

            var refreshToken = new RefreshToken()
            {
                RToken = refreshTokenId,
                ClientId = clientId,
                UserName = context.Ticket.Identity.Name,
                IssuedTime = DateTime.UtcNow,
                ExpiresTime = DateTime.UtcNow.AddSeconds(Convert.ToDouble(refreshTokenLifeTime)),
                ProtectedTicket = context.SerializeTicket()
            };

            context.Ticket.Properties.IssuedUtc = refreshToken.IssuedTime;
            context.Ticket.Properties.ExpiresUtc = refreshToken.ExpiresTime;

            if (await _refreshTokenService.Save(refreshToken))
            {
                context.SetToken(refreshTokenId);
            }
        }

        public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            if (string.IsNullOrWhiteSpace(context.Token))
                return;

            //从数据库取出refresh token
            var refreshToken = await _refreshTokenService.Get(context.Token);

            if (refreshToken != null)
            {
                context.DeserializeTicket(refreshToken.ProtectedTicket);
                var result = await _refreshTokenService.Remove(context.Token);
            }
        }

        public void Create(AuthenticationTokenCreateContext context)
        {
            throw new NotImplementedException();
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            if (_refreshTokenService != null)
                _refreshTokenService.Dispose();
        }
    }
}